define(["dijit/_WidgetBase",
        "dijit/_TemplatedMixin",
        "dojo/_base/declare",
        "dojo/text!./Object2ObjectWidget/templates/Object2ObjectWidget.html",
        "dojo/_base/array",
        "dojo/dom-construct",
        "dojo/_base/lang",
        "dojo/on"],
        function(_WidgetBase,_TemplatedMixin,declare,template,array,dom,lang,on) {
	
	return declare("Object2ObjectWidget", [_WidgetBase,_TemplatedMixin], {
		formField: "undefined",
		targetLabel: "Removed objects",
		sourceLabel: "Assigned objects",
		disabled: false,
		_disabledStr: "",
		size: 5,
		add_label: "add",
		add_image_url: "/SolutionManager/resources/images/resultset_previous.png",
		add_image_url_disabled: "/SolutionManager/resources/images/resultset_previous_disabled.png",
		remove_label: "remove",
		remove_image_url: "/SolutionManager/resources/images/resultset_next.png",
		remove_image_url_disabled: "/SolutionManager/resources/images/resultset_next_disabled.png",
		selectedIds: "",
		idProperty: 'id',
		displayProperty: 'label',
		argumentObjects: [],
		templateString: template,
	    postMixInProperties: function() {
	    	this.inherited(arguments);
	    	if (this.disabled === true || this.disabled === "true") {
	    		this._disabledStr = 'disabled';
	    		this.add_image_url = this.add_image_url_disabled;
	    		this.remove_image_url = this.remove_image_url_disabled;
	    	}
	    },
	    postCreate: function() {
	    	this.inherited(arguments);
	    	var addObjFunc = function(selectNode,object) {
	    		dom.create("option", 
    				{innerHTML: object[this.displayProperty], value: object[this.idProperty]}, selectNode);
	    	};
	    	this.processArgumentObjects(this.readIDs(this.selectedIds),
    			lang.hitch(this,addObjFunc,this.targetSelectNode),
    			lang.hitch(this,addObjFunc,this.sourceSelectNode));
	    	// set up button handlers only if widget isn't disabled
	    	if (this._disabledStr !== 'disabled') {
		    	var handleMoveFunc = function(fromNode,toNode) {
		    		this.processSelected(fromNode,
	    				function(item) {
		    				this.moveItem(item,toNode);
						}.bind(this));
		    		// update IDs in hidden
		    		var items = [];
		    		array.forEach(this.targetSelectNode.getElementsByTagName("option"),
	    				function(item) {
	    					items.push(item.value);
	    				});
		    		this.hiddenInputNode.value = this.writeIDs(items);
		    	};
		    	on(this.addButton, "click",
	    			lang.hitch(this,handleMoveFunc,this.sourceSelectNode,this.targetSelectNode));
		    	on(this.removeButton, "click",
	    			lang.hitch(this,handleMoveFunc,this.targetSelectNode,this.sourceSelectNode));
	    	}
	    },
	    processArgumentObjects: function(idsArray, selectedFunc, notSelectedFunc) {
	    	array.forEach(this.argumentObjects, function(object) {
	    		if (array.indexOf(idsArray, object[this.idProperty]) === -1) {    			
	    			notSelectedFunc(object);
	    		} else {
	    			selectedFunc(object);
	    		}
	    	}.bind(this));
	    },
	    moveItem: function(item, selectNode) {
	    	dom.create("option", {innerHTML: item.innerHTML, value: item.value}, selectNode);
	    	dom.destroy(item);
	    },
	    processSelected: function(selectNode, processFunc) {
	    	var items = selectNode.getElementsByTagName("option");
	    	array.forEach(items, function(item) {
	    		// workaround because of forEach behavior - we may destroy members of items array in processFunc, so undefined could happen
	    		if (item !== undefined && item.selected) {
	    			processFunc(item);
	    		}
	    	});
	    },
	    /* read delimited ids from string, return array*/
	    readIDs: function(idsString) {
	    	idsArray = idsString.split(',');
	    	return idsArray;
	    },
	    /* write ids from array to string*/
	    writeIDs: function(idsArray) {
	    	result = '';
	    	array.forEach(idsArray, function(id, index) {
	    		if (index === 0) {
	    			result = id;
	    		} else {
	    			result = result +','+ id;
	    		}
			});
	    	return result;
	    }		
	});
	
});